package com.hctforgreen.greenservice.utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 当应用捕获到未处理的异常后将异常信息记录方便调试
 * 存储的内容有：日期
 * 异常信息，手机型号，APP版本
 * Created by 390697 on 2016/11/5.
 */
public class ApplicationCrashHandleUtil implements Thread.UncaughtExceptionHandler {

    /**
     * 调试时Log日志的tag
     * String			:		TAG
     */
    private static final String TAG = "NorrisInfo";

    private static ApplicationCrashHandleUtil mInstance = new ApplicationCrashHandleUtil();

    private Thread.UncaughtExceptionHandler mDefaultHandler;

    private Context context;

    private String saveLogPath;

    private HashMap<String,String> logMap = new HashMap<String, String>();

    private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyyMMdd_HH-mm-ss") ;

    //单例模式--懒汉模式
    private ApplicationCrashHandleUtil() {

    }

    public static ApplicationCrashHandleUtil getInstance() {
        return mInstance;
    }

    //设置保存log的路径
    public void setLogPath(String path) {
        this.saveLogPath = path;
    }


    public void init(Context context) {
        this.context = context;
        // 获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // 设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    /**
     * The thread is being terminated by an uncaught exception. Further
     * exceptions thrown in this method are prevent the remainder of the
     * method from executing, but are otherwise ignored.
     *
     * @param thread the thread that has an uncaught exception
     * @param ex     the exception that was thrown
     */
    @Override
    public void uncaughtException(Thread thread, final Throwable ex) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                LogUtil.e(TAG, ex.getMessage(), ex);
            }
        }).start();

        if (!handleException(ex) && mDefaultHandler != null) {
            //如果遇到的异常，自定义的异常处理器没有处理，则让系统默认的异常处理器处理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            //处理了
            try {
                thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    //	handleException:{自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.}
    public boolean handleException(Throwable paramThrowable) {
        if (paramThrowable == null)
            return false;

        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                //可以做提示 关闭退出程序
                //Toast.makeText(mContext , "很抱歉,程序出现异常,即将退出" , 0).show() ;
                Looper.loop();
            }
        }).start();

        getDeviceInfo();

        saveCrashLogToFile(paramThrowable);

        return true;

    }

    private void getDeviceInfo(){
        try {
            // 获得包管理器
            PackageManager packageManager = context.getPackageManager();
            // 得到该应用的信息，即主Activity
            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
            if(packageInfo != null) {
                String versionName = packageInfo.versionName == null ? "null"
                        : packageInfo.versionName ;
                String versionCode = packageInfo.versionCode + "" ;
                logMap.put("versionName" , versionName) ;
                logMap.put("versionCode" , versionCode) ;
            }

        }catch (Exception e){
            e.printStackTrace();
        }

        // 反射机制
        Field[] mFields = Build.class.getDeclaredFields() ;
        // 迭代Build的字段key-value  此处的信息主要是为了在服务器端手机各种版本手机报错的原因
        for(Field field : mFields) {
            try {
                field.setAccessible(true) ;
                logMap.put(field.getName() , field.get("").toString()) ;
                LogUtil.d(TAG , field.getName() + ":" + field.get("")) ;
            }
            catch(IllegalArgumentException e) {
                e.printStackTrace() ;
            }
            catch(IllegalAccessException e) {
                e.printStackTrace() ;
            }
        }
    }

    private void saveCrashLogToFile(Throwable paramThrowable){

        StringBuffer buffer = new StringBuffer();
        for (Map.Entry<String,String> entry : logMap.entrySet()){
            String key = entry.getKey();
            String value = entry.getValue();
            buffer.append(key + "=" + value + "\r\n");
        }

        Writer writer = new StringWriter();
        PrintWriter printWriter = new PrintWriter(writer);
        paramThrowable.printStackTrace(printWriter);
        Throwable throwable = paramThrowable.getCause();
        // 迭代栈队列把所有的异常信息写入writer中
        while (throwable != null){
            paramThrowable.printStackTrace(printWriter);
            //换行
            printWriter.append("\r\n");
            throwable = paramThrowable.getCause();
        }

        printWriter.close();
        String result = writer.toString();
        buffer.append(result);
        String date = mSimpleDateFormat.format(new Date());
        String fileName = "CrashLog-" + date + ".log";
        //文件
        try {
            File fileDirectory = new File(saveLogPath);
            if (!fileDirectory.exists()) {
                fileDirectory.mkdir();
            }
            FileOutputStream mFileOutputStream = new FileOutputStream(fileDirectory + "/"
                    + fileName);
            mFileOutputStream.write(buffer.toString().getBytes());
            mFileOutputStream.close();


        }catch (Exception e){
            e.printStackTrace();
        }



    }
}
